home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 February / EnigmA AMIGA RUN 04 (1996)(G.R. Edizioni)(IT)[!][issue 1996-02][Skylink CD III].iso / earcd / midi / rustle.lha / Rustle / Source / Rustle.mod < prev   
Text File  |  1995-12-02  |  12KB  |  453 lines

  1. (**************************************************************************
  2.  
  3. :Remark.            Format: ein TAB in jeder 3. Spalte: ..tab..tab..tab..
  4.  
  5.  
  6. :Program.        Rustle
  7.  
  8. :Contents.        plays white noise
  9.  
  10. :Bugs.            "Shit happens." (Murphy)
  11.  
  12.  
  13. :Copyright.        Freeware---you may copy and use it, but all rights remain
  14. :Copyright.        at the author
  15.  
  16. :Author.            Thomas Ansorge
  17.  
  18. :Address.        Dinkelackerring 55, 67435 Neustadt, Deutschland, Europa
  19.  
  20.  
  21. :Language.        Modula-2
  22.  
  23. :Translator.    M2Amiga V4.3 (deutsch)
  24.  
  25.  
  26. :History.        1.0 as of 22-Apr-95: seems to work...
  27.  
  28.  
  29. **************************************************************************)
  30.  
  31. (*$ DEFINE DEBUG := FALSE *)
  32.  
  33.  
  34. MODULE Rustle;
  35.  
  36. FROM Arts IMPORT Assert, BreakPoint, returnVal, Terminate, wbStarted;
  37.  
  38. FROM Audio IMPORT allocate, allocFailed, audioName, channelStolen, free, IOAudio, IOAudioPtr, lock, noWait, pervol;
  39.  
  40. FROM DosD IMPORT ctrlC, fail, RDArgsPtr;
  41.  
  42. FROM DosL IMPORT Delay, FreeArgs, ReadArgs;
  43.  
  44. FROM ExecD IMPORT IOFlagSet, IORequest, MemReqs, MemReqSet, MsgPort, Message, MessagePtr, MsgPortPtr, Node, write;
  45.  
  46. FROM ExecL IMPORT AbortIO, AllocMem, CloseDevice, CopyMem, CreateMsgPort, DeleteMsgPort, execVersion, FindTask, FreeMem, GetMsg, OpenDevice, Signal, Wait;
  47.  
  48. FROM ExecSupport IMPORT BeginIO;
  49.  
  50. FROM GraphicsD IMPORT DisplayFlags, DisplayFlagSet, GfxBase, GfxBasePtr;
  51.  
  52. FROM GraphicsL IMPORT graphicsBase;
  53.  
  54. (*
  55. Es muß nicht \source{Randoms} sein, jeder Zufallszahlengenerator sollte es tun...
  56. *)
  57.  
  58. FROM Randoms IMPORT Rand0, ReduceToByte;
  59.  
  60. FROM SYSTEM IMPORT ADDRESS, ADR, CAST, LONGSET, SHIFT, SHORTSET;
  61.  
  62. FROM Terminal IMPORT WriteLn, WriteString;
  63.  
  64. (* --------------------------------------------------------------------- *)
  65.  
  66. CONST
  67.     prog_str = "Rustle 1.0/";
  68.     date_str = "(22.04.95)";
  69.  
  70.     (*$ IF M68881 OR M68040 *)
  71.         ver_str = prog_str + "68020+FPU " + date_str;
  72.     (*$ ELSIF M68020 *)
  73.         ver_str = prog_str + "68020 " + date_str;
  74.     (*$ ELSIF M68010 *)
  75.         ver_str = prog_str + "68010 " + date_str;
  76.     (*$ ELSE *)
  77.         ver_str = prog_str + "68000 " + date_str;
  78.     (*$ ENDIF *)
  79.     
  80.     ver_ptr = ADR ("$VER: " + ver_str);
  81.  
  82. CONST
  83.     exec_min_version = 36;
  84.     
  85. CONST
  86.     rustle_buffer_size = 32 * 1024; (* Bytes *)
  87.     
  88.     frequency = 400 * 5000; (* 5000? *)
  89.     
  90. CONST
  91.     template = "VOLUME/N";
  92.  
  93. TYPE
  94.     ChannelArray = ARRAY [0..1] OF SHORTSET;
  95.  
  96. CONST
  97.     left_channels = ChannelArray {SHORTSET {1}, SHORTSET {2}};
  98.     right_channels = ChannelArray {SHORTSET {0}, SHORTSET {3}};
  99.  
  100. TYPE
  101.     Status = (doing_nothing, allocating, playing, freeing, quitting);
  102.     Location = (back_home, outside);
  103.     
  104.     IOAudioRec = RECORD
  105.         io: IOAudio;
  106.         status: Status;
  107.         location: Location;
  108.     END; (* RECORD IOAudioRec *)
  109.     
  110.     IOAudioRecPtr = POINTER TO IOAudioRec;
  111.  
  112. VAR
  113.     (* Pointer *)
  114.     data_ptr: ADDRESS;
  115.     dummy_msg_ptr: IOAudioRecPtr;
  116.     play_port_ptr: MsgPortPtr;
  117.     rdargs_ptr: RDArgsPtr;
  118.     vol: LONGINT;
  119.     vol_ptr: POINTER TO LONGINT;
  120.     
  121.     (* anderes 32bit Zeug *)
  122.     ctrlc_sig: LONGSET;
  123.     play_sig: LONGSET;
  124.     sigs: LONGSET;
  125.     
  126.     (* anderes *)
  127.     alloc_key: INTEGER;
  128.     left_play_req: IOAudioRec;
  129.     right_play_req: IOAudioRec;
  130.  
  131. VAR (* Flags *)
  132.     audio_open := BOOLEAN {FALSE};
  133.     quit := BOOLEAN {FALSE};
  134.     runtime_error := BOOLEAN {TRUE};
  135.     
  136. (* --------------------------------------------------------------------- *)
  137.  
  138. PROCEDURE Err (condition: BOOLEAN; msg: ARRAY OF CHAR); FORWARD;
  139.     
  140. (* --------------------------------------------------------------------- *)
  141.     
  142. PROCEDURE AbortChannel (VAR play_rec: IOAudioRec);
  143.     
  144.     BEGIN (* Prozedur AbortChannel *)
  145.         
  146.     IF play_rec.location = outside THEN
  147.         AbortIO (ADR (play_rec));
  148.                     
  149.     ELSE (* IF play_req.location = outside THEN *)
  150.         Err (FALSE, ver_str + ": message not in use!");
  151.     END; (* IF play_req.location = outside THEN *)
  152. END AbortChannel; (* Prozedur *)
  153.     
  154. (* --------------------------------------------------------------------- *)
  155.     
  156. PROCEDURE AllocChannel (VAR play_req: IOAudioRec; channels: ChannelArray; key: INTEGER);
  157.     
  158.     (* play_req MUSS VAR sein wegen ADR (play_req) weiter unten!!! *)
  159.     
  160.     BEGIN (* Prozedur AllocChannel *)
  161.         IF play_req.location = back_home THEN
  162.             play_req.io.request.message.node.pri := -100;
  163.             play_req.io.request.unit := NIL;
  164.             play_req.io.request.command := allocate;
  165.             play_req.io.request.flags := noWait;
  166.             play_req.io.request.error := 0;
  167.             play_req.io.allocKey := key;
  168.             play_req.io.data := ADR (channels);
  169.             play_req.io.length := SIZE (channels);
  170.             play_req.io.period := 0;
  171.             play_req.io.volume := 0;
  172.             play_req.io.cycles := 0;
  173.             
  174.             play_req.status := allocating;
  175.             play_req.location := outside;
  176.             
  177.             BeginIO (ADR (play_req));
  178.                 
  179.         ELSE (* IF play_req.location = back_home THEN *)
  180.             Err (FALSE, ver_str + ": message already in use!");
  181.         END; (* IF play_req.location = back_home THEN *)
  182.     END AllocChannel; (* Prozedur *)
  183.     
  184. (* --------------------------------------------------------------------- *)
  185.  
  186. (*
  187. Diese Prozedur bricht das Programm sauber und kontextabhängig (Workbench oder 
  188. CLI) ab, falls \source{condition = FALSE}. Dabei wird \source{msg} als Fehlertext
  189. ausgegeben.
  190. *)
  191.  
  192. PROCEDURE Err (condition: BOOLEAN; msg: ARRAY OF CHAR);
  193.     
  194.     BEGIN (* Prozedur Err *)
  195.     
  196.     IF wbStarted THEN
  197.         Assert (condition, ADR (msg));
  198.     
  199.     ELSE (* IF wbStarted *)
  200.         IF NOT condition THEN
  201.             WriteString (msg);
  202.             WriteLn;
  203.             
  204.             returnVal := fail;
  205.             Terminate ();
  206.         END; (* If NOT condition *)
  207.     END; (* IF wbStarted *)
  208. END Err; (* Prozedur *)
  209.     
  210. (* --------------------------------------------------------------------- *)
  211.     
  212. PROCEDURE HandlePlayMessage (VAR play_req: IOAudioRec; channels: ChannelArray; key: INTEGER);
  213.     
  214.     (* play_req MUSS VAR sein wegen ADR (...) weiter unten!!! *)
  215.     
  216.     (* global: data_ptr *)
  217.         
  218.     (* ------------------------------------------------------------------ *)
  219.  
  220.     PROCEDURE GetAudioConstant (): LONGCARD;
  221.         
  222.         BEGIN (* Funktion GetAudioConstant *)
  223.         
  224.         IF pal IN graphicsBase^.displayFlags THEN
  225.             RETURN 3546895;
  226.             
  227.         ELSE (* IF pal IN graphicsBase^.displayFlags *)
  228.             RETURN 3579545;
  229.         END; (* IF pal IN graphicsBase^.displayFlags THEN ELSE *)
  230.     END GetAudioConstant; (* Funktion *)
  231.         
  232.     (* ------------------------------------------------------------------ *)
  233.  
  234.     BEGIN (* Prozedur HandlePlayMessage *)
  235.     
  236.     CASE play_req.status OF
  237.         |allocating:
  238.             IF play_req.location = back_home THEN
  239.                 IF play_req.io.request.error = 0 THEN
  240.                     WITH  play_req.io DO
  241.                         request.command := write;
  242.                         request.flags := pervol; (* = 12, SHORTSET {3, 2} *)
  243.                         data := data_ptr;
  244.                         length := rustle_buffer_size;
  245.                         period := GetAudioConstant () DIV frequency;
  246.                         
  247.                         IF vol_ptr # NIL THEN
  248.                             volume := vol_ptr^;
  249.                         
  250.                         ELSE (* IF vol_ptr # NIL *)
  251.                             volume := 4;
  252.                         END; (* IF vol_ptr # NIL THEN ELSE *)
  253.                         
  254.                         cycles := 0;
  255.                     END; (* WITH  play_req.io.request *)
  256.     
  257.                     play_req.status := playing;
  258.                     play_req.location := outside;
  259.                     
  260.                     BeginIO (ADR (play_req));
  261.                 
  262.                 ELSIF play_req.io.request.error = allocFailed THEN
  263.                     IF NOT quit THEN
  264.                         Delay (100);
  265.                         AllocChannel (play_req, channels, key);
  266.                     
  267.                     ELSE (* IF NOT quit THEN *)
  268.                         play_req.status := quitting;
  269.                     END; (* IF NOT quit THEN *)
  270.                     
  271.                 ELSE (* IF play_req.io.request.error = 0 *)
  272.                     Err (FALSE, ver_str + ": allocation failed!");
  273.                 END; (* IF play_req.io.request.error = 0 *)
  274.             
  275.             ELSE (* IF play_req.location = back_home THEN *)
  276.                 Err (FALSE, ver_str + ": message already in use!");
  277.             END; (* IF play_req.location = back_home THEN *)
  278.  
  279.         |playing:
  280.             IF NOT quit THEN
  281.                 AllocChannel (play_req, channels, key);
  282.             
  283.             ELSE (* IF NOT quit THEN *)
  284.                 play_req.status := quitting;
  285.             END; (* IF NOT quit ELSE *)
  286.     END; (* CASE play_req.status OF *)
  287. END HandlePlayMessage; (* Prozedur *)
  288.     
  289. (* --------------------------------------------------------------------- *)
  290.  
  291. (*
  292. Für weißes Rauschen brauchen wir einen zufällig gefüllten Bereich CHIP-Speicher.
  293. *)
  294.  
  295. PROCEDURE InitRustleBuffer (): ADDRESS;
  296.     
  297.     TYPE
  298.         RustleBuffer = ARRAY [1..rustle_buffer_size] OF SHORTCARD;
  299.         RustleBufferPtr = POINTER TO RustleBuffer;
  300.     
  301.     VAR
  302.         buffer_ptr: RustleBufferPtr;
  303.         
  304.         i: [1..rustle_buffer_size];
  305.     
  306.     BEGIN (* Funktion InitRustleBuffer *)
  307.         buffer_ptr := AllocMem (rustle_buffer_size, MemReqSet {public, chip});
  308.         Err (buffer_ptr # NIL, ver_str + ": no chip memory, no rustle.");
  309.         
  310.         FOR i := 1 TO rustle_buffer_size DO
  311.             buffer_ptr^ [i] := ReduceToByte (Rand0 ());
  312.         END; (* FOR i := 1 TO rustle_buffer_size *)
  313.         
  314.         RETURN buffer_ptr;
  315.     END InitRustleBuffer; (* Funktion *)
  316.  
  317. (* --------------------------------------------------------------------- *)
  318. (* --------------------------------------------------------------------- *)
  319.  
  320. BEGIN (* Program Rustle *)
  321.     Err (execVersion >= exec_min_version, ver_str + ": Kickstart 2.0 Minimum!");
  322.     
  323.     IF wbStarted THEN
  324.     ELSE (* IF wbStarted *)
  325.         rdargs_ptr := ReadArgs (ADR (template), ADR (vol_ptr), NIL);
  326.     END; (* IF wbStarted ELSE *)
  327.     
  328.     IF vol_ptr # NIL THEN
  329.         IF (vol_ptr^ < 0) OR (vol_ptr^ > 64) THEN
  330.             WriteString (ver_str + ": 0 <= VOLUME <= 64, using default (4)");
  331.             WriteLn;
  332.             
  333.             vol_ptr := NIL;
  334.         END; (* IF (vol_ptr^ < 0) OR (vol_ptr^ > 64) THEN *)
  335.     END; (* IF vol_ptr # NIL THEN *)
  336.     
  337.     data_ptr := InitRustleBuffer ();
  338.     
  339.     ctrlc_sig := CAST (LONGSET, SHIFT (LONGINT (1), ctrlC));
  340.     
  341.     play_port_ptr := CreateMsgPort ();
  342.     Err (play_port_ptr # NIL, ver_str + ": no message port to open Audio.device!");
  343.     play_sig := CAST (LONGSET, SHIFT (LONGINT (1), play_port_ptr^.sigBit));
  344.     
  345.     left_play_req.io.request.message.replyPort := play_port_ptr;
  346.     
  347.     OpenDevice (ADR (audioName), 0, ADR (left_play_req.io), LONGSET {});
  348.     Err (left_play_req.io.request.error = 0, ver_str + ": Audio.device did not open!");
  349.     audio_open := TRUE;
  350.     
  351.     CopyMem (ADR (left_play_req), ADR (right_play_req), SIZE (left_play_req));
  352.     
  353.     alloc_key := left_play_req.io.allocKey;
  354.     
  355.     left_play_req.location := back_home;
  356.     right_play_req.location := back_home;
  357.     
  358.     REPEAT
  359.         IF left_play_req.status = doing_nothing THEN
  360.             AllocChannel (left_play_req, left_channels, alloc_key);
  361.         END; (* IF left_play_req.status = doing_nothing *)
  362.  
  363. (*
  364. Solange wir keinen \source{allocKey} vom Audio-Device haben, dürfen wir nur
  365. den einen Kanal alloziieren und müssen warten, bis wir ihn haben.
  366. *)
  367.  
  368.         IF alloc_key # 0 THEN
  369.             IF right_play_req.status = doing_nothing THEN
  370.                 AllocChannel (right_play_req, right_channels, alloc_key);
  371.             END; (* IF right_play_req.status = doing_nothing *)
  372.         END; (* IF alloc_key # 0 *)
  373.         
  374.         sigs := Wait (ctrlc_sig + play_sig);
  375.  
  376. (* 
  377. Ein Play-Request kam zurück. Normalerweise passiert das hier nur in den 
  378. folgenden Fällen:\begin{itemize}
  379. \item Ein Kanal wurde gerade (hoffentlich) erfolgreich alloziiert.
  380. \item Ein Kanal wurde uns genommen.
  381. \item Ein Kanal wurde mit \source{AbortIO ()} abgebrochen.
  382. \end{itemize}
  383. *)
  384.         
  385.         IF play_sig <= sigs THEN
  386.             dummy_msg_ptr := GetMsg (play_port_ptr);
  387.             
  388.             IF dummy_msg_ptr # NIL THEN
  389.                 Signal (FindTask (NIL), play_sig);
  390.                 
  391.                 IF alloc_key = 0 THEN
  392.                     alloc_key := dummy_msg_ptr^.io.allocKey;
  393.                 END; (* IF alloc_key = 0 THEN *)
  394.                 
  395.                 dummy_msg_ptr^.location := back_home;
  396.                 
  397.                 IF dummy_msg_ptr = ADR (left_play_req) THEN
  398.                     HandlePlayMessage (left_play_req, left_channels, alloc_key);
  399.                     
  400.                 ELSIF dummy_msg_ptr = ADR (right_play_req) THEN
  401.                     HandlePlayMessage (right_play_req, right_channels, alloc_key);
  402.                 
  403.                 ELSE (* Hey, was ist das bloß für eine Nachricht??? *)
  404.                     Err (FALSE, ver_str + ": got unexpected message (???)");
  405.                 END; (* ELSIF dummy_msg_ptr = ADR (right_play_req) ELSE *)
  406.             END; (* IF dummy_msg_ptr # NIL *)
  407.         END; (* IF play_sig <= sigs *)
  408.         
  409. (*
  410. Control-C? Wenn ja, Schleife verlassen, aufräumen, Programm beenden.
  411. *)
  412.  
  413.         IF ctrlc_sig <= sigs THEN
  414.             WriteString ("***Break");
  415.             WriteLn;
  416.             
  417.             AbortChannel (left_play_req);
  418.             AbortChannel (right_play_req);
  419.             
  420.             quit := TRUE;
  421.             
  422.             (*$ IF DEBUG *)
  423.             Terminate ();
  424.             (*$ ENDIF *)
  425.         END; (* IF ctrlc_sig <= sigs *)
  426.     UNTIL (left_play_req.status = quitting) AND (right_play_req.status = quitting);
  427.                 
  428.     runtime_error := FALSE;
  429.     
  430. CLOSE; (* -------------------------------------------------------------- *)
  431.     IF NOT runtime_error THEN
  432.         IF audio_open THEN
  433.             CloseDevice (ADR (left_play_req.io));
  434.             audio_open := FALSE;
  435.         END; (* IF audio_open *)
  436.         
  437.         IF play_port_ptr # NIL THEN
  438.             DeleteMsgPort (play_port_ptr);
  439.             play_port_ptr := NIL;
  440.         END; (* IF play_port_ptr # NIL *)
  441.         
  442.         IF data_ptr # NIL THEN
  443.             FreeMem (data_ptr, rustle_buffer_size);
  444.             data_ptr := NIL;
  445.         END; (* IF data_ptr # NIL *)
  446.     END; (* IF NOT runtime_error THEN *)
  447.     
  448.     IF rdargs_ptr # NIL THEN
  449.         FreeArgs (rdargs_ptr);
  450.         rdargs_ptr := NIL;
  451.     END; (* IF rdargs_ptr # NIL THEN *)
  452. END Rustle.
  453.